"""
Filename: globals_gwaste.jl
Paper: Unemployment and the Distribution of Liquidity
Authors: Zach Bethune and Guillaume Rocheteau
Contact: bethune@rice.edu
Last Modified: 8/22/23
Purpose: holds global structure definitions, moments used in calibration, functional forms, etc.
"""

###############################################################################
# Structures
###############################################################################
#holds model parameters
mutable struct parmsmodel
    A #level of early utility
    a #curvature of early utility
    D #level of late utility
    d #curvature of late utility
    b #curvature of production possibility frontier
    C #level of matching function
    c #curvature of matching function
    DELTA #job destruction rate
    ELL #utility of leisure
    ALPHA #prob of liquidity shock
    ALPHAmf #conditional prob access financial wealth
    meanZ #mean of productivity distribution
    BETA #discount factor
    rho #discount rate
    K #fixed entry cost
    π_l #proportion of low skilled type
    π_m #proportion of middle skilled
    parmsmodel() = new()
end

#holds model outcomes (e.g. decision rules, distributions, etc.)
mutable struct model_outcomes
    agrid
    zgrid
    Wa
    Wa_p
    a_p
    am_p
    c
    ystar
    g
    emp
    theta
    Yd
    Ys
    Jd
    Js
    Zmd
    py
    Rm
    Rf
    frev
    wages_bar
    tau
    wages
    T
    PI
    Ag
    gz
    ga
    model_outcomes() = new()
end

#holds moments computed from model steady state
mutable struct model_moments
    G 
    G1 
    G0 
    gmi 
    Gmi
    li_range
    gls 
    Gls
    ls_range
    gwi 
    Gwi 
    wi_range
    gini
    liquid_share
    liquid_to_income
    gbonds_share
    equity_share 
    wealth_to_income 
    liquid_prem 
    model_moments() = new()
end

#holds empirical moments
mutable struct moments_data
    LABOR_SHARE
    PROFIT_SHARE
    JOB_FINDING
    JOB_FILLING
    JOB_SEPARATION
    REPLACE_RATE
    Rm_moment
    Rf_moment
    SKILL_PREMIUM
    BOND_SHARE
    TOP_INC_SHARE
    MKP
    moments_data() = new()
end

###############################################################################
# Empirical Moments
###############################################################################
md = moments_data();
md.LABOR_SHARE = 0.7; #labor share of 70%
md.PROFIT_SHARE = 0.10; #profit share of 10%
md.JOB_FINDING = 0.3; #job finding rate
md.JOB_FILLING = 0.90629; #job filling rate
md.JOB_SEPARATION = 0.04; #job separation rate
md.REPLACE_RATE = 0.40; #income replace rate
md.Rm_moment = (1.0-0.014)^(1.0/12.0); #real return on money (MZM in data)
md.Rf_moment = (1.048)^(1.0/12.0); #real return on (partially) illiquid wealth (targets real user cost of 6.2%)
md.SKILL_PREMIUM = 1.7; #skill premium
md.BOND_SHARE = 0.13; #average share of bonds in household wealth
md.TOP_INC_SHARE = 0.25; #top 10% share of income
md.MKP = 1.3; #retail markup of 30%

###############################################################################
# Global program parameters
###############################################################################
const Nz = 3; #dimension of productivity vector
const Na = 100; #dimension of wealth vector
const agrid_min = 1e-10;
const agrid_max = 110.0;
const Wa_tol = 1e-5;
const Wa_iter_max = 10000;
const fiscal_tol = 1e-3;
const fiscal_iter_max = 10;
const mkt_clear_calib_inner_tol=1e-5;

###############################################################################
# Functional Forms
###############################################################################
#Early consumption preferences
function υ(y;parms)
    if y.>=0
        return (parms.A./(1.0-parms.a)).*((y).^(1.0-parms.a))
    else
        return -1e20
    end
end

function υ_prime(y;parms)
    if y<=0.0
        return 1e10
    else
        return parms.A*(y)^(-parms.a)
    end
end

function υ_prime_inv(x;parms)
    if x<=0.0
        return 1e50
    else
        return (parms.A./x).^(1.0/parms.a)
    end
end

#Late consumption preferences 
function u(c;parms) 
    if c>=0 # 
        # return log(c) 
        return (parms.D/(1.0-parms.d))*((c)^(1.0-parms.d) - 1.0) 
    else 
        return -1e20 
    end 
end 

function u_prime(c;parms) 
    return parms.D*(c^-parms.d) 
end 

function u_prime_inv(x;parms) 
    if x<=0.0 
        return 1e50 
    else 
        return (parms.D./x)^(1.0/parms.d) 
    end 
end 

#Firm's cost, marginal cost, and inverse marginal cost functions 
function κ(y;parms) 
    return 1.0 .- (1.0.-y^(1.0/parms.b))^parms.b
end 

function κ_prime(y;parms) 
    return return ((1-y^(1/parms.b))^(parms.b-1))*(y^((1-parms.b)/parms.b))
end 

function κ_prime_prime(y;parms)
    return (1-parms.b)*(((y^(-1/parms.b))-y)^(parms.b-2))*(1+(1/parms.b)*y^(-1-(1/parms.b)))
end

function κ_prime_inv(p;parms) 
    return 1/((1+(p^(1/(parms.b-1))))^parms.b)
end

function mkp(y;parms)
    return κ_prime(y;parms)*y/κ(y;parms)
end

#Job finding rate and inverse 
function λ(theta;parms) 
    return parms.C/((1.0+theta^(-parms.c))^(1.0/parms.c)) 
end 
function λ_prime(theta;parms)
    return (parms.C.*theta^(-parms.c+1.0))/((1.0+theta^(-parms.c))^((1.0/parms.c)+1.0))
end 
function λ_inv(x;parms) 
    return (((parms.C/x)^parms.c)-1.0)^(-1.0/parms.c) 
end 

#Job filling rate and inverse 
function q(x;parms) 
    return parms.C/(1.0+x^parms.c)^(1.0/parms.c) 
end 

function q_inv(x;parms) 
    return (((parms.C/x)^parms.c)-1.0)^(1.0/parms.c) 
end 

#define f=1/q, then solve for f inverse
function f(theta;parms)
    return (1.0/parms.C)*(theta^parms.c+1.0)^(1.0/parms.c)
end

function f_prime(theta;parms)
    return (1.0/parms.c)*(1.0/parms.C)*(theta^parms.c+1.0)^((1.0/parms.c)-1.0)*parms.c*(theta^(parms.c-1.0))
end

function f_inv(x;parms)
    return ((x*parms.C)^parms.c-1.0)^(1.0/parms.c)
end

function firm_profits(py;parms)
    Ys = κ_prime_inv.(py;parms);
    frev = 1.0 .+ py.*Ys .- κ.(Ys;parms);
    wage1 = md.LABOR_SHARE.*frev;
    return frev-wage1
end

function firm_rev(py;parms)
    return 1.0 + py*κ_prime_inv(py;parms) - κ(κ_prime_inv(py;parms);parms)
end

function mkp(py;parms)
    return (py*κ_prime_inv(py;parms))/κ(κ_prime_inv(py;parms);parms)
end

#END